﻿using Bot.Domain.SessionChat;



using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Bot.Domain.Report
{
    public enum EnumChatType
    {
        AgentOnly = 0,
        ChatbotOnly = 1,
        ChatbotToAgent = 2,
        
    }

    public class ChatsItem : BaseReportInfoItem
    {
      
        public int BotResolved { get; set; }
        public int BotUnResolved { get; set; }

        public int BotTransferredAgent { get; set; }

        public int BotTransferredOfflineMessage { get; set; }

        [JsonConverter(typeof(LongConvert))]
        public long AgentChatTime { get; set; }
        [JsonConverter(typeof(LongConvert))]
        public long BotChatTime { get; set; }

        [JsonIgnore]
        public int ChatsCount { get; set; }

        [JsonIgnore]
        public int AgentOnlyCount { get; set; }
      
        public override string GetValue(int i)
        {
            switch (i)
            {
                case 0:
                    return this.BotResolved.ToString();
                case 1:
                    return this.BotUnResolved.ToString();
                case 2:
                    return this.BotTransferredAgent.ToString();
                case 3:
                    return this.BotTransferredOfflineMessage.ToString();
                case 4:
                    return format(this.BotChatTime);
                case 5:
                    return format(this.AgentChatTime);
                default:
                    return "";
            }
        }

        private string format(long time)
        {
            long longValue = Convert.ToInt64(time);
            //D.HH:MM:SS
            //D为天，HH为小时，MM为分钟，SS为秒
            long second = 0;
            long day = Math.DivRem(longValue, 60 * 60 * 24, out second);
            long hour = Math.DivRem(second, 60 * 60, out second);
            long minute = Math.DivRem(second, 60, out second);

            return string.Format("{0}.{1}:{2}:{3}", day, hour.ToString("00"), minute.ToString("00"), second.ToString("00"));
        }
    }
    public class ChatsInfo : BaseReportInfo<ChatsItem>
    {
        [JsonIgnore]
        public int TotalChats { get; set; }
        [JsonIgnore]
        public int TotalAgentOnly { get; set; }

        public int TotalBotResolved { get; set; }
        public int TotalBotUnResolved { get; set; }
        public int TotalBotTransferredAgent { get; set; }
        public int TotalBotTransferredOfflineMessage { get; set; }
        [JsonConverter(typeof(LongConvert))]
        public long TotalAgentChatTime { get; set; }
        [JsonConverter(typeof(LongConvert))]
        public long TotalBotChatTime { get; set; }

        [JsonIgnore]
        public override List<string> FieldList {
            get
            {
                return new List<string>() {
                    "Bot Resolved",
                    "Bot Unresolved",
                    "Bot Unresolved-Transferred to Online Agent",
                    "Bot Unresolved-Transferred to Offline Message",
                    "Bot Chat Time",
                    "Agent Chat Time"
                };
            }
        }
        public override string GetValue(int i)
        {
            switch (i)
            {
                case 0:
                    return this.TotalBotResolved.ToString();
                case 1:
                    return this.TotalBotUnResolved.ToString();
                case 2:
                    return this.TotalBotTransferredAgent.ToString();
                case 3:
                    return this.TotalBotTransferredOfflineMessage.ToString();
                case 4:
                    return format(this.TotalBotChatTime);
                case 5:
                    return format(this.TotalAgentChatTime);
                default:
                    return "";
            }
        }

        private string format(long time)
        {
            long longValue = Convert.ToInt64(time);
            //D.HH:MM:SS
            //D为天，HH为小时，MM为分钟，SS为秒
            long second = 0;
            long day = Math.DivRem(longValue, 60 * 60 * 24, out second);
            long hour = Math.DivRem(second, 60 * 60, out second);
            long minute = Math.DivRem(second, 60, out second);

            return string.Format("{0}.{1}:{2}:{3}", day, hour.ToString("00"), minute.ToString("00"), second.ToString("00"));
        }
    }
    public class ChatsEntityInfo
    {
        public IList<SessionChatDto> ChatsEntityList { get; set; }
    }

    public class ChatsWrap : BasicWrap<ChatsItem, ChatsInfo, ChatsEntityInfo>
    {
        
        public static ChatsInfo GetChats(SearchCriteria search, ChatsEntityInfo entityInfo, bool ifEncode = true)
        {
            //System.Diagnostics.Stopwatch watch = new System.Diagnostics.Stopwatch();
            //watch.Start();

            //ChatSourceEntityInfo entityInfo = ChatSourceProcess.GetChatSourceData(search); //数据库查询出来的数据

            //System.Diagnostics.Debug.WriteLine("Access Time: " + watch.Elapsed);
            //watch.Reset();
            //watch.Start();
            //System.Diagnostics.Debug.WriteLine(entityInfo.ChatSourceEntityList.Count);
            //System.Diagnostics.Debug.WriteLine(entityInfo.ChatSourceNumEntityList.Count);

            ChatsInfo result = new ChatsInfo();
            
            //UTCToLocal(ref entityInfo);
            switch (search.dimensionType)
            {
                case EnumDimensionType.ByTime://by time
                //case EnumDimensionType.AllChannel:
                //case EnumDimensionType.DefaultChannel:
                //case EnumDimensionType.LivechatChannel:
                //case EnumDimensionType.FacebookChannel:
                //case EnumDimensionType.TwitterChannel:
                    result = GetInfoByTime(search, entityInfo, PushByTimeData, null, null);
                    break;
               
            }

            //watch.Stop();
            //System.Diagnostics.Debug.WriteLine("Calc Time: " + watch.Elapsed);
            return result;
        }

        //search the chat Source info for campaign by criteria
        private static ChatsInfo GetChatsByDimension(SearchCriteria search, ChatsEntityInfo entityInfo, bool ifEncode)
        {
            var result = new ChatsInfo();
            //result.dataType = EnumReportDataType.DataByDimension;
            //List<SessionChatDto> data = entityInfo.ChatsEntityList.Where(a=>a.CodePlanId == int.Parse(search.filterStr)).ToList();

            //result.TotalChats = data.Count;
            //if (search.dimensionType == EnumDimensionType.ByDepartment)
            //{
            //    result.TotalAgentOnly = data.Count(a=>a.ChatType== (int)EnumChatType.AgentOnly);
            //    result.TotalChatbotOnly = data.Count(a => a.ChatType == (int)EnumChatType.ChatbotOnly);
            //    result.TotalFromBotToAgent = data.Count(a => a.ChatType == (int)EnumChatType.ChatbotToAgent);
            //}

            //result.dataList = new List<ChatsItem>();

            //foreach (var item in data)
            //{
            //    var newItem = new ChatsItem();
            //    newItem.tableRowName = GetTableRowName(ifEncode, item.RequestTime);
            //    newItem.fieldId = item.FieldId;
            //    newItem.chatCount = item.Chats;
            //    newItem.chatPercentage = CalcPercent(item.Chats, result.totalChatCount);
            //    if (search.dimensionType == EnumDimensionType.ByDepartment)
            //    {
            //        newItem.fromChatButtonCount = item.ChatButtons;
            //        newItem.fromChatButtonPercentage = CalcPercent(item.ChatButtons, result.totalFromChatButtonCount);
            //        newItem.fromManuallyInvitationCount = item.ManuallyInvitations;
            //        newItem.fromManuallyInvitationPercentage = CalcPercent(item.ManuallyInvitations, result.totalFromManuallyInvitationCount);
            //        newItem.fromAutoInvitationCount = item.AutoInvitations;
            //        newItem.fromAutoInvitationPercentage = CalcPercent(item.AutoInvitations, result.totalFromAutoInvitationCount);
            //    }

            //    newItem.startTime = search.startDate.ToString();
            //    newItem.startTimeDate = search.startDate;
            //    newItem.endTime = search.endDate.ToString();
            //    newItem.endTimeDate = search.endDate;
            //    result.dataList.Add(newItem);
            //}

            //result.dataList = result.dataList.OrderByDescending(o => o.Time).ToList();
            return result;
        }

        private static ChatsInfo PushByTimeData(ChatsInfo result, ChatsEntityInfo entityInfo, SearchCriteria search)
        {
         

            List<SessionChatDto> ChatsEntityList = entityInfo.ChatsEntityList.OrderBy(c => c.RequestTime).ToList();
            int[] onlyBotStatus = new int[] { 0, 1, 2 };
            foreach (ChatsItem chatitem in result.dataList)
            {
                List<SessionChatDto> todayChatsEntityList = ChatsEntityList.Where(a => Today(chatitem, a.RequestTime,search.timeOffset)).ToList();

                //chatitem.AgentOnlyCount = todayChatsEntityList.Count(a => a.Status == 0 && a.ChatType == (int)EnumChatType.AgentOnly);
                chatitem.BotResolved = todayChatsEntityList.Count(a => onlyBotStatus.Contains(a.Status) && a.ChatType == (int)EnumChatType.ChatbotOnly&& a.OfflineMessageId == Guid.Empty);
                chatitem.BotTransferredAgent = todayChatsEntityList.Count(a => a.Status==0 && a.ChatType == (int)EnumChatType.ChatbotToAgent);
                chatitem.BotTransferredOfflineMessage = todayChatsEntityList.Count(a => onlyBotStatus.Contains(a.Status) && a.ChatType == (int)EnumChatType.ChatbotOnly&&a.OfflineMessageId!= Guid.Empty);
                chatitem.BotUnResolved = chatitem.BotTransferredAgent + chatitem.BotTransferredOfflineMessage;


                chatitem.ChatsCount = chatitem.AgentOnlyCount + chatitem.BotResolved + chatitem.BotTransferredAgent;

                chatitem.AgentChatTime = CalcuChatTimeService.GetAgentTotalTime(todayChatsEntityList);
                chatitem.BotChatTime = CalcuChatTimeService.GetBotTotalTime(todayChatsEntityList);
                
                result.TotalBotResolved += chatitem.BotResolved;
                result.TotalBotUnResolved += chatitem.BotUnResolved;
                result.TotalBotTransferredAgent += chatitem.BotTransferredAgent;
                result.TotalBotTransferredOfflineMessage += chatitem.BotTransferredOfflineMessage;

                result.TotalAgentChatTime += chatitem.AgentChatTime;
                result.TotalBotChatTime += chatitem.BotChatTime;

                result.TotalAgentOnly += chatitem.AgentOnlyCount;
                result.TotalChats += chatitem.ChatsCount;
            }

            //int lindex = 0;
            //foreach (var item in ChatsEntityList)
            //{  
            //    item.RequestTime = DateTimeHelper.UTCToLocal(item.RequestTime); 

            //    ChatsItem chatitem = result.dataList[lindex];
            //    while (item.RequestTime >= chatitem.endTimeDate && lindex < result.dataList.Count)
            //    {
            //        lindex++;
            //        chatitem = result.dataList[lindex];
            //    }
            //    chatitem.ChatsCount++;
            //    result.TotalChats++;
            //    switch (item.ChatType)
            //    {
            //        case (int)EnumChatType.AgentOnly:
            //            chatitem.AgentOnlyCount++;
            //            result.TotalAgentOnly++;
            //            break;
            //        case (int)EnumChatType.ChatbotOnly:
            //            chatitem.BotOnlyCount++;
            //            result.TotalChatbotOnly++;
            //            break;
            //        case (int)EnumChatType.ChatbotToAgent:
            //            chatitem.BotToAgentCount++;
            //            result.TotalFromBotToAgent++;
            //            break;
            //        default:
            //            break;
            //    }
            //}

            GetListTotal(ref result, search);

            result.dataList = result.dataList.Reverse().ToList();

            return result;
        }


        private static bool Today(ChatsItem chatsItem,DateTime utcDate,TimeSpan timeOffset)
        {
            Guid operatorId = Guid.Empty;
            operatorId = SessionHelper.GetSessionValue_CurrentOperatorId();
            DateTime localDate = DateTimeHelper.UtcToLocal(utcDate, operatorId);
            return localDate >= chatsItem.startTimeDate && localDate< chatsItem.endTimeDate;
        }
        private static ChatsInfo PushByTimeDataWith24_7Distribution(ChatsInfo result, ChatsEntityInfo entityInfo, SearchCriteria search)
        {
            int[] numDays = CountDays(search.startDate, search.endDate);
            foreach (SessionChatDto chat in entityInfo.ChatsEntityList)
            {
                Guid operatorId = Guid.Empty;
                operatorId = SessionHelper.GetSessionValue_CurrentOperatorId();
                DateTime requestTimeLocal = DateTimeHelper.UtcToLocal(chat.RequestTime, operatorId); 

                int index = (int)requestTimeLocal.DayOfWeek * hournum + requestTimeLocal.Hour;

                result.dataList[index].ChatsCount++;
                result.TotalChats++;
                switch (chat.ChatType)
                {
                    case (int)EnumChatType.AgentOnly:
                        result.dataList[index].AgentOnlyCount++;
                        result.TotalAgentOnly++;
                        break;
                    case (int)EnumChatType.ChatbotOnly:
                        result.dataList[index].BotResolved++;
                        result.TotalBotResolved++;
                        break;
                    case (int)EnumChatType.ChatbotToAgent:
                        result.dataList[index].BotTransferredAgent++;
                        result.TotalBotTransferredAgent++;
                        break;
                    default:
                        break;
                }          
            }

            foreach (ChatsItem item in result.dataList)
            {
                int num = numDays[item.IndexNum / hournum];
                if (num > 0)
                {
                    item.ChatsCount = item.ChatsCount;
                    item.AgentOnlyCount = item.AgentOnlyCount;
                    item.BotResolved = item.BotResolved;
                    item.BotTransferredAgent = item.BotTransferredAgent;
                }
                else
                {
                    item.ChatsCount = 0;
                    item.AgentOnlyCount = 0;
                    item.BotResolved = 0;
                    item.BotTransferredAgent = 0;
                }
                result.dataByTimeWithDistribution[item.IndexNum / hournum].dataByTimeList.Add(item);
            }
            result.dataList = new List<ChatsItem>();
            GetListTotal(ref result, search);
            return result;
        }

        private static ChatsInfo PushByTimeDataWith48HalfHourDistribution(ChatsInfo result, ChatsEntityInfo entityInfo, SearchCriteria search)
        {
            int dayNum = GetDays(search.startDate, search.endDate);

            foreach (SessionChatDto chat in entityInfo.ChatsEntityList)
            {
                Guid operatorId = Guid.Empty;
                operatorId = SessionHelper.GetSessionValue_CurrentOperatorId();
                DateTime requestTimeLocal = DateTimeHelper.UtcToLocal(chat.RequestTime, operatorId); 

                int index = requestTimeLocal.Hour * 2 + (requestTimeLocal.Minute < 30 ? 0 : 1);

                result.dataList[index].ChatsCount++;
                result.TotalChats++;
                switch (chat.ChatType)
                {
                    case (int)EnumChatType.AgentOnly:
                        result.dataList[index].AgentOnlyCount++;
                        result.TotalAgentOnly++;
                        break;
                    case (int)EnumChatType.ChatbotOnly:
                        result.dataList[index].BotResolved++;
                        result.TotalBotResolved++;
                        break;
                    case (int)EnumChatType.ChatbotToAgent:
                        result.dataList[index].BotTransferredAgent++;
                        result.TotalBotTransferredAgent++;
                        break;
                    default:
                        break;
                }

            }

            foreach (ChatsItem item in result.dataList)
            {
                if (dayNum > 0)
                {
                    item.ChatsCount = item.ChatsCount;
                    item.AgentOnlyCount = item.AgentOnlyCount;
                    item.BotResolved = item.BotResolved;
                    item.BotTransferredAgent = item.BotResolved;
                }
                else
                {
                    item.ChatsCount = 0;
                    item.AgentOnlyCount = 0;
                    item.BotResolved = 0;
                    item.BotTransferredAgent = 0;
                }
            }

            GetListTotal(ref result, search);

            return result;
        }

        private static void GetListTotal(ref ChatsInfo result, SearchCriteria search)
        {
            //对数据进行格式化的，取小数位2，平均值

            double divNum = 0;
            if (search.timeUnit == EnumTimeIntervalType.Distribution24_7Hour)
            {
                divNum = GetWeeksInDateRange(search.startDate, search.endDate);
            }
            else if (search.timeUnit == EnumTimeIntervalType.Distribution48HalfHour)
            {
                divNum = GetDays(search.startDate, search.endDate);
            }
            else
            {
                result.TotalChats = result.TotalChats;
                result.TotalAgentOnly = result.TotalAgentOnly;
                result.TotalBotResolved = result.TotalBotResolved;
                result.TotalBotTransferredAgent = result.TotalBotTransferredAgent;
            }

            if (search.timeUnit == EnumTimeIntervalType.Distribution24_7Hour || search.timeUnit == EnumTimeIntervalType.Distribution48HalfHour)
            {
                result.TotalChats = result.TotalChats;
                result.TotalAgentOnly = result.TotalAgentOnly;
                result.TotalBotResolved = result.TotalBotResolved;
                result.TotalBotTransferredAgent = result.TotalBotTransferredAgent;
            }
        }

        #region export

        //search the New Export CSV Data for Chat Source Info by criteria
        public static NewExportCSVData GetExprotData(SearchCriteria search, ChatsEntityInfo entityInfo)
        {
            ChatsInfo info = GetChats(search, entityInfo, false);
            NewExportCSVData result = new NewExportCSVData(string.Empty, new List<NewCSVColumn>(), new DataTable());
            switch (search.dimensionType)
            {
                case EnumDimensionType.ByTime://by time
                case EnumDimensionType.ByDepartment://by department
                case EnumDimensionType.ChatbotChats://by department
                //case EnumDimensionType.AllChannel:
                //case EnumDimensionType.FacebookChannel:
                //case EnumDimensionType.LivechatChannel:
                //case EnumDimensionType.TwitterChannel:
                case EnumDimensionType.ChatbotAnswers://by department
                case EnumDimensionType.ChatbotHightFidenceAnswers://by department
                    {
                        result = GetExprotCSVData(search, info, info.FieldList);
                        break;
                    }
                case EnumDimensionType.RequestPage:
                    {
                        result = GetExprotCSVData(search, info, new List<string>() { info.FieldList[0] });
                        break;
                    }
            }
            return result;
        }

        #endregion

    }

    public class LongConvert : JsonConverter
    {
        public LongConvert() { }
        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            throw new NotImplementedException();
        }
        public override bool CanConvert(Type objectType)
        {
            return true;
        }
        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            if(value == null)
            {
                writer.WriteNull();
                return;
            }

            long longValue = Convert.ToInt64(value);
            //D.HH:MM:SS
            //D为天，HH为小时，MM为分钟，SS为秒
            long second = 0;
            long day = Math.DivRem(longValue, 60 * 60 * 24, out second);
            long hour = Math.DivRem(second, 60 * 60, out second);
            long minute = Math.DivRem(second, 60, out second);

            writer.WriteValue(string.Format("{0}.{1}:{2}:{3}", day, hour.ToString("00"), minute.ToString("00"), second.ToString("00")));
        }
    }
}
